home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / jnos110g.zip / DIALER.C < prev    next >
C/C++ Source or Header  |  1994-08-26  |  16KB  |  616 lines

  1. /* Automatic SLIP/PPP line dialer.
  2.  *
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  *  Mar '91 Bill Simpson & Glenn McGregor
  6.  *      completely re-written;
  7.  *      human readable control file;
  8.  *      includes wait for string, and speed sense;
  9.  *      dials immediately when invoked.
  10.  *  May '91 Bill Simpson
  11.  *      re-ordered command line;
  12.  *      allow dial only;
  13.  *      allow inactivity timeout without ping.
  14.  *  Sep '91 Bill Simpson
  15.  *      Check known DTR & RSLD state for redial decision
  16.  *
  17.  * Mods by PA0GRI (newsession parameters)
  18.  *
  19.  * Mods by KF8NH:  iffailed, begin/end
  20.  */
  21. #include <ctype.h>
  22. #include "global.h"
  23. #ifdef DIALER
  24. #include "mbuf.h"
  25. #include "timer.h"
  26. #include "proc.h"
  27. #include "iface.h"
  28. #include "netuser.h"
  29. #ifdef LINUX
  30. #include "lxasy.h"
  31. #else
  32. #include "i8250.h"
  33. #endif
  34. #include "asy.h"
  35. #include "tty.h"
  36. #include "session.h"
  37. #include "socket.h"
  38. #include "cmdparse.h"
  39. #include "devparam.h"
  40. #include "icmp.h"
  41. #include "files.h"
  42. #include "main.h"
  43. #include "trace.h"
  44.   
  45. #define MIN_INTERVAL    5L
  46. #define MAXDEPTH      8
  47.   
  48. static int Failmode = 0;
  49. static char Failed;
  50. static char Depth;
  51. static char Skip[MAXDEPTH];
  52. static char SkipOverride;
  53. static char OverrideDepth;
  54.   
  55. static int redial __ARGS((struct iface *ifp,char *file));
  56.   
  57. static int dodial_nothing     __ARGS((int argc,char *argv[],void *p));
  58. static int dodial_begin       __ARGS((int argc,char *argv[],void *p));
  59. static int dodial_control __ARGS((int argc,char *argv[],void *p));
  60. static int dodial_end     __ARGS((int argc,char *argv[],void *p));
  61. static int dodial_exit        __ARGS((int argc,char *argv[],void *p));
  62. static int dodial_failmode    __ARGS((int argc,char *argv[],void *p));
  63. static int dodial_iffail  __ARGS((int argc,char *argv[],void *p));
  64. static int dodial_ifok                __ARGS((int argc,char *argv[],void *p));
  65. static int dodial_send      __ARGS((int argc,char *argv[],void *p));
  66. static int dodial_speed     __ARGS((int argc,char *argv[],void *p));
  67. static int dodial_status    __ARGS((int argc,char *argv[],void *p));
  68. static int dodial_wait      __ARGS((int argc,char *argv[],void *p));
  69.   
  70. static struct cmds dial_cmds[] = {
  71.     "",     dodial_nothing, 0, 0, "",
  72.     "begin",    dodial_begin,   0, 1, "begin",
  73.     "control",  dodial_control, 0, 2, "control up | down",
  74.     "end",      dodial_end, 0, 1, "end",
  75.     "exit",     dodial_exit,    0, 1, "exit",
  76.     "failmode", dodial_failmode,0, 2, "failmode on | off",
  77.     "iffail",   dodial_iffail,  0, 2, "iffail \"command\"",
  78.     "ifok",         dodial_ifok,    0, 2, "ifok \"command\"",
  79.     "send",     dodial_send,    0, 2,
  80.     "send \"string\" [<milliseconds>]",
  81.     "speed",    dodial_speed,   0, 2, "speed <bps>",
  82.     "status",   dodial_status, 0, 2, "status up | down",
  83.     "wait",     dodial_wait,    0, 2,
  84.     "wait <milliseconds> [ \"string\" [speed] ]",
  85.     NULLCHAR,   NULLFP,     0, 0, "Unknown command",
  86. };
  87.   
  88.   
  89. /* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
  90.  *  <iface>     must be asy type
  91.  *  <filename>  contains commands which are executed.
  92.  *          missing: kill outstanding dialer.
  93.  *  <seconds>   interval to check for activity on <iface>.
  94.  *  <pings>     number of missed pings before redial.
  95.  *  <hostid>    interface to ping.
  96.  */
  97. int
  98. dodialer(argc,argv,p)
  99. int argc;
  100. char *argv[];
  101. void *p;
  102. {
  103.     struct iface *ifp;
  104.     struct asy *ap;
  105.     int32 interval = 0L;        /* in seconds */
  106.     int32 last_wait = 0L;
  107.     int32 target = 0L;
  108.     int pings = 0;
  109.     int countdown;
  110.     char *filename;
  111.     char *ifn;
  112.     int result;
  113.     int s;
  114.   
  115.     if((ifp = if_lookup(argv[1])) == NULLIF){
  116.         tprintf(Badinterface,argv[1]);
  117.         return 1;
  118.     }
  119.     if( ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp ){
  120.         tprintf("Interface %s not asy port\n",argv[1]);
  121.         return 1;
  122.     }
  123.   
  124.     if(ifp->supv != NULLPROC){
  125.         while ( ifp->supv != NULLPROC ) {
  126.             alert(ifp->supv, EABORT);
  127.             pwait(NULL);
  128.         }
  129.         tprintf("dialer terminated on %s\n",argv[1]);
  130.     }
  131.   
  132.     if ( argc < 3 ) {
  133.         /* just terminating */
  134.         return 0;
  135.     }
  136.   
  137.     chname( Curproc, ifn = if_name( ifp, " dialer" ) );
  138.     free( ifn );
  139.     filename = rootdircat(argv[2]);
  140.   
  141.     /* handle minimal command (just thru filename) */
  142.     if ( argc < 4 ) {
  143.         /* just dialing */
  144.         result = redial(ifp, filename);
  145.   
  146.         if ( filename != argv[2] )
  147.             free(filename);
  148.         return result;
  149.   
  150.     /* get polling interval (arg 3) */
  151.     } else if ( (interval = atol(argv[3])) <= MIN_INTERVAL ) {
  152.         tprintf("interval must be > %ld seconds\n", MIN_INTERVAL);
  153.         return 1;
  154.     }
  155.   
  156.     /* get the number of pings before redialing (arg 4) */
  157.     if ( argc < 5 ) {
  158.     } else if ( (pings = atoi(argv[4])) <= 0 ){
  159.         tprintf("pings must be > 0\n");
  160.         return 1;
  161.     }
  162.   
  163.     /* retrieve the host name (arg 5) */
  164.     if ( argc < 6 ) {
  165.     } else if ( (target = resolve(argv[5])) == 0L ) {
  166.         tprintf(Badhost,argv[5]);
  167.         return 1;
  168.     }
  169.   
  170.     countdown = pings;
  171.     ifp->supv = Curproc;
  172.     ap = &Asy[ ifp->dev ];
  173.   
  174.     while ( !main_exit ) {
  175.         int32 wait_for = interval;
  176.   
  177.         /*
  178.          * N.B. Eventually, when the rest of this is stable, I will
  179.          * look into supporting DTR and RTS.  For now, it's enough to
  180.          * just have the Linux version of the code work.
  181.          */
  182. #ifndef LINUX
  183.         if ( ap->dtr_usage == FOUND_DOWN
  184.             ||  ap->dtr_usage == MOVED_DOWN
  185.         ||  ap->rlsd_line_control == MOVED_DOWN ) {
  186.             /* definitely down */
  187.             if ( redial(ifp,filename) < 0 )
  188.                 break;
  189.         } else
  190. #endif
  191.             if ( ifp->lastrecv >= last_wait ) {
  192.             /* got something recently */
  193.                 wait_for -= secclock() - ifp->lastrecv;
  194.                 countdown = pings;
  195.             } else if ( countdown < 1 ) {
  196.             /* we're down, or host we ping is down */
  197.                 if ( redial(ifp,filename) < 0 )
  198.                     break;
  199.                 countdown = pings;
  200.             } else if ( target != 0L
  201.             && (s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) != -1 ) {
  202.                 pingem(s,target,0,(int16)s,0);
  203.                 close_s(s);
  204.                 countdown--;
  205.             } else if ( ifp->echo != NULLFP ) {
  206.                 (*ifp->echo)(ifp,NULLBUF);
  207.                 countdown--;
  208.             }
  209.   
  210.         last_wait = secclock();
  211.         if ( wait_for != 0L ) {
  212.             alarm( wait_for * 1000L );
  213.             if ( pwait( &(ifp->supv) ) == EABORT )
  214.                 break;
  215.             alarm(0L);      /* clear alarm */
  216.         }
  217.     }
  218.   
  219.     if ( filename != argv[2] )
  220.         free(filename);
  221.     ifp->supv = NULLPROC;   /* We're being terminated */
  222.     return 0;
  223. }
  224.   
  225.   
  226. /* execute dialer commands
  227.  * returns: -1 fatal error, 0 OK, 1 try again
  228.  */
  229. static int
  230. redial( ifp, file )
  231. struct iface *ifp;
  232. char *file;
  233. {
  234.     char *inbuf, *intmp;
  235.     FILE *fp;
  236.     int (*rawsave) __ARGS((struct iface *,struct mbuf *));
  237.     struct session *sp;
  238.     int result = 0;
  239.     int save_input = Curproc->input;
  240.     int save_output = Curproc->output;
  241.   
  242.     if((fp = fopen(file,READ_TEXT)) == NULLFILE){
  243.         tprintf("redial: can't read %s\n",file);
  244.         return -1;  /* Causes dialer proc to terminate */
  245.     }
  246.     /* Save output handler and temporarily redirect output to null */
  247.     if(ifp->raw == bitbucket){
  248.         tprintf("redial: tip or dialer already active on %s\n",ifp->name);
  249.         return -1;
  250.     }
  251.   
  252.     /* allocate a session descriptor */
  253.     if ( (sp = newsession( ifp->name, DIAL, 0 )) == NULLSESSION ) {
  254.         tputs(TooManySessions);
  255.         return 1;
  256.     }
  257.     tprintf( "Dialing on %s\n\n", ifp->name );
  258.   
  259.     /* Save output handler and temporarily redirect output to null */
  260.     rawsave = ifp->raw;
  261.     ifp->raw = bitbucket;
  262.   
  263.     /* Suspend the packet input driver. Note that the transmit driver
  264.      * is left running since we use it to send buffers to the line.
  265.      */
  266.     suspend(ifp->rxproc);
  267.   
  268. #ifdef notdef
  269.     tprintf("rlsd: 0x%02x, dtr: 0x%02x\n",
  270.     Asy[ifp->dev].rlsd_line_control,
  271.     Asy[ifp->dev].dtr_usage );
  272. #endif
  273.   
  274.     Failed = 0;
  275.     Depth = 0;
  276.     Skip[0] = 0;
  277.     SkipOverride = -1;
  278.   
  279.     inbuf = mallocw(BUFSIZ);
  280.     intmp = mallocw(BUFSIZ);
  281.     while ( fgets( inbuf, BUFSIZ, fp ) != NULLCHAR ) {
  282.         strcpy(intmp,inbuf);
  283.         rip( intmp );
  284.         log( -1, "%s dialer: %s", ifp->name, intmp );
  285.         if( (result = cmdparse(dial_cmds,inbuf,ifp)) != 0 ){
  286.             if (Failmode)
  287.                 Failed = 1;
  288.             else
  289.             {
  290.                 tprintf("input line: %s",intmp);
  291.                 break;
  292.             }
  293.         }
  294.         else
  295.             Failed = 0;
  296.         if (Depth == -1)
  297.             break;
  298.         if (SkipOverride != -1)
  299.         {
  300.             Skip[OverrideDepth] = SkipOverride;
  301.             SkipOverride = -1;
  302.         }
  303.     }
  304.     if (Depth > 0)
  305.         tprintf("Warning: %d unmatched `begin's in command file\n", Depth);
  306.     free(inbuf);
  307.     free(intmp);
  308.     fclose(fp);
  309.   
  310.     if ( result == 0 ) {
  311.         ifp->lastsent = ifp->lastrecv = secclock();
  312.     }
  313.   
  314.     ifp->raw = rawsave;
  315.     resume(ifp->rxproc);
  316.     tprintf( "\nDial %s complete\n", ifp->name );
  317.   
  318.     /* Wait for awhile, so the user can read the screen,
  319.      * AND to give it time to send some packets on the new connection!
  320.      */
  321.     /* ten seconds is an AWFULLY long time...
  322.     pause( 10000L );
  323.     */
  324.     pause(2000L);
  325.     freesession( sp );
  326.     Curproc->input = save_input;
  327.     Curproc->output = save_output;
  328.     return result;
  329. }
  330.   
  331.   
  332. static int
  333. dodial_control(argc,argv,p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337. {
  338.     struct iface *ifp = p;
  339.     int param;
  340.   
  341.     if (Skip[Depth])
  342.         return 0;
  343.   
  344.     tprintf("control %s %ld\n", argv[1], atol(argv[2]));
  345.     if ( ifp->ioctl == NULL )
  346.         return -1;
  347.   
  348.     if ( (param = devparam( argv[1] )) == -1 )
  349.         return -1;
  350.   
  351.     (*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
  352.     return 0;
  353. }
  354.   
  355.   
  356. static int
  357. dodial_send(argc,argv,p)
  358. int argc;
  359. char *argv[];
  360. void *p;
  361. {
  362.     struct iface *ifp = p;
  363.     struct mbuf *bp;
  364.   
  365.     if (Skip[Depth])
  366.         return 0;
  367.   
  368.     tprintf("send <%s>\n", argv[1]);
  369.     if(argc > 2){
  370.         /* Send characters with inter-character delay
  371.          * (for dealing with prehistoric Micom switches that
  372.          * can't take back-to-back characters...yes, they
  373.          * still exist.)
  374.          */
  375.         char *cp;
  376.         int32 cdelay = atol(argv[2]);
  377.   
  378.         for(cp = argv[1];*cp != '\0';cp++){
  379.             bp = qdata(cp,1);
  380.             asy_send(ifp->dev,bp);
  381.             pause(cdelay);
  382.         }
  383.     } else {
  384.         bp = qdata( argv[1], (int16)strlen(argv[1]) );
  385.   
  386.         if (ifp->trace & IF_TRACE_RAW)
  387.             raw_dump( ifp, IF_TRACE_OUT, bp );
  388.         asy_send( ifp->dev, bp );
  389.     }
  390.     return 0;
  391. }
  392.   
  393.   
  394. static int
  395. dodial_speed(argc,argv,p)
  396. int argc;
  397. char *argv[];
  398. void *p;
  399. {
  400.     struct iface *ifp = p;
  401.   
  402.     if (Skip[Depth])
  403.         return 0;
  404.   
  405.     if ( argc < 2 ) {
  406.         tprintf( "current speed = %lu bps\n", Asy[ifp->dev].speed );
  407.         return 0;
  408.     }
  409.     tprintf("speed %ld\n", atol(argv[1]));
  410.     return asy_speed( ifp->dev, atol( argv[1] ) );
  411. }
  412.   
  413.   
  414. static int
  415. dodial_status(argc,argv,p)
  416. int argc;
  417. char *argv[];
  418. void *p;
  419. {
  420.     struct iface *ifp = p;
  421.     int param;
  422.   
  423.     if (Skip[Depth])
  424.         return 0;
  425.   
  426.     if ( ifp->iostatus == NULL )
  427.         return -1;
  428.   
  429.     if ( (param = devparam( argv[1] )) == -1 )
  430.         return -1;
  431.   
  432.     (*ifp->iostatus)( ifp, param, atol( argv[2] ) );
  433.     return 0;
  434. }
  435.   
  436.   
  437. static int
  438. dodial_wait(argc,argv,p)
  439. int argc;
  440. char *argv[];
  441. void *p;
  442. {
  443.     struct iface *ifp = p;
  444.     register int c = -1;
  445.   
  446.     if (Skip[Depth])
  447.         return 0;
  448.   
  449.     alarm( atol( argv[1] ) );
  450.   
  451.     if ( argc == 2 ) {
  452.         tprintf("wait %ld\nimsg <", atol(argv[1]));
  453.         tflush();
  454.         while ( (c = get_asy(ifp->dev)) != -1 ) {
  455.             tputc( c &= 0x7F );
  456.             tflush();
  457.         }
  458.         alarm( 0L );
  459.         tprintf(">\n");
  460.         return 0;
  461.     } else {
  462.         register char *cp = argv[2];
  463.   
  464.         tprintf("waitfor <%s>\nimsg <", argv[2]);
  465.         tflush();
  466.         while ( *cp != '\0'  &&  (c = get_asy(ifp->dev)) != -1 ) {
  467.             tputc( c &= 0x7F );
  468.             tflush();
  469.   
  470.             if (*cp++ != c) {
  471.                 cp = argv[2];
  472.             }
  473.         }
  474.   
  475.         if ( argc > 3 ) {
  476.             if ( stricmp( argv[3], "speed" ) == 0 ){
  477.                 int32 speed = 0;
  478.   
  479.                 while ( (c = get_asy(ifp->dev)) != -1 ) {
  480.                     tputc( c &= 0x7F );
  481.                     tflush();
  482.   
  483.                     if ( isdigit(c) ) {
  484.                         speed *= 10;
  485.                         speed += c - '0';
  486.                     } else {
  487.                         alarm( 0L );
  488.                         tprintf("> ok\n");
  489.                         return asy_speed( ifp->dev, speed );
  490.                     }
  491.                 }
  492.             } else {
  493.                 tprintf("> bad command\n");
  494.                 return -1;
  495.             }
  496.         }
  497.     }
  498.     alarm( 0L );
  499.     tprintf("> %s\n", (c == -1? "failed": "ok"));
  500.     return ( c == -1 );
  501. }
  502.   
  503. static int
  504. dodial_failmode(argc, argv, p)
  505. int argc;
  506. char **argv;
  507. void *p;
  508. {
  509.     if (Skip[Depth])
  510.         return 0;
  511.     tprintf("failmode %s\n", argv[1]);
  512.     return setbool(&Failmode, "Continue on dial command failure", argc, argv);
  513. }
  514.   
  515. static int
  516. dodial_iffail(argc, argv, p)
  517. int argc;
  518. char **argv;
  519. void *p;
  520. {
  521.     if (!Skip[Depth])
  522.     {
  523.         if (SkipOverride == -1)
  524.         {
  525.             SkipOverride = Skip[Depth];
  526.             OverrideDepth = Depth;
  527.         }
  528.         Skip[Depth] = !Failed;
  529.     }
  530.     return cmdparse(dial_cmds, argv[1], p);
  531. }
  532.   
  533. static int
  534. dodial_ifok(argc, argv, p)
  535. int argc;
  536. char **argv;
  537. void *p;
  538. {
  539.     if (!Skip[Depth])
  540.     {
  541.         if (SkipOverride == -1)
  542.         {
  543.             SkipOverride = Skip[Depth];
  544.             OverrideDepth = Depth;
  545.         }
  546.         Skip[Depth] = Failed;
  547.     }
  548.     return cmdparse(dial_cmds, argv[1], p);
  549. }
  550.   
  551. static int
  552. dodial_begin(argc, argv, p)
  553. int argc;
  554. char **argv;
  555. void *p;
  556. {
  557.     if (Depth == MAXDEPTH)
  558.     {
  559.         Depth = -1;
  560.         tputs("Blocks nested too deeply\n");
  561.         return -1;
  562.     }
  563.     if (!Skip[Depth])
  564.         tputs("begin\n");
  565.     Skip[Depth + 1] = Skip[Depth];
  566.     Depth++;
  567.     return 0;
  568. }
  569.   
  570. static int
  571. dodial_end(argc, argv, p)
  572. int argc;
  573. char **argv;
  574. void *p;
  575. {
  576.     if (!Skip[Depth])
  577.         tputs("end\n");
  578.     if (Depth-- == 0)
  579.     {
  580.         tputs("`end' without `begin'\n");
  581.         return -1;
  582.     }
  583.     return 0;
  584. }
  585.   
  586. static int
  587. dodial_exit(argc, argv, p)
  588. int argc;
  589. char **argv;
  590. void *p;
  591. {
  592.     if (Skip[Depth])
  593.         return 0;
  594.     if (argc > 1)
  595.         tprintf("exit %d\n", atoi(argv[1]));
  596.     else
  597.         tputs("exit\n");
  598.     Depth = -1;
  599.     return (argc > 1? atoi(argv[1]): Failed);
  600. }
  601.   
  602. /*
  603.  * cmdparse sends blank lines to the first command, sigh
  604.  */
  605.   
  606. static int
  607. dodial_nothing(argc, argv, p)
  608. int argc;
  609. char **argv;
  610. void *p;
  611. {
  612.     return 0;
  613. }
  614. #endif /* DIALER */
  615.   
  616.